﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using FlyingAPI;
using System.Net;
using FlickrNet;
using TagSpider.Properties;

namespace TagSpider
{
    class TagSpiderController
    {
        public enum TagSpiderStatus { STATUS_STOP, STATUS_PAUSE, STATUS_WORKING };

        private static TagSpiderController instance;
        private string flickrapiKey;
        private string flickrsharedSecret;
        private int producerNum;
        private int consumerNum;

        private LogAppend WritelnLog;
        private FlyingPig flyingPig;

        public FlyingPig FlyingPig
        {
            get { return flyingPig; }
            set { flyingPig = value; }
        }

        private ConsumeAndProduceFactory.ConsumeAndProduceFactory factory;

        public ConsumeAndProduceFactory.ConsumeAndProduceFactory Factory
        {
            get { return factory; }
            set { factory = value; }
        }

        private SearchJob searchJob;

        public SearchJob SearchJob
        {
            get { return searchJob; }
            set { searchJob = value; }
        }
        
        private TagSpiderController(LogAppend g)
        {
            WritelnLog = g;
            flyingPig = new FlyingPig();
            // 初始化状态
            m_DownloadStatus = TagSpiderStatus.STATUS_STOP;
            flickrapiKey = Settings.Default.flickrapiKey;
            flickrsharedSecret = Settings.Default.flickrsharedSecret;
            producerNum = Settings.Default.producerNum;
            consumerNum = Settings.Default.consumerNum;
           
            // 初始化factory
            factory = new ConsumeAndProduceFactory.ConsumeAndProduceFactory(producerNum, consumerNum, 10);
            factory.Consuming += new ConsumeAndProduceFactory.FactoryEventHandler(uploadImageInfos);
            factory.Producing += new ConsumeAndProduceFactory.FactoryEventHandler(spideImageInfos);
            factory.OnceConsume = 1;

        }
        public static TagSpiderController getInstance(LogAppend g)
        {
            if (instance == null)
            {
                instance = new TagSpiderController(g);
            }

            return instance;
        }
        public void start()
        {
            // 启动生产者消费者模型
            int a = factory.startwork();
            WritelnLog(a.ToString());

            // 启动完factory后，设置状态
            m_DownloadStatus = TagSpiderStatus.STATUS_WORKING;
        }

        public void pause()
        {
            // 暂停factory
            factory.pausework();

            // 暂停完factory后，设置状态
            m_DownloadStatus = TagSpiderStatus.STATUS_PAUSE;
        }

        public void stop()
        {
            // 停止factory
            factory.stopwork();

            // 停止完factory后，设置状态
            m_DownloadStatus = TagSpiderStatus.STATUS_STOP;
        }

        public void resume()
        {
            // 恢复
            factory.resumework();

            // 启动完factory后，设置状态
            m_DownloadStatus = TagSpiderStatus.STATUS_WORKING;
        }

        public TagSpiderStatus getCurStatus()
        {
            return m_DownloadStatus;
        }

        private TagSpiderStatus m_DownloadStatus;


        // 生产
        public void spideImageInfo(object sender, ConsumeAndProduceFactory.FactoryEventArgs e)
        {
            JobPage mainJobPage = FlyingPig.requestJobPage(searchJob.SearchJobId);

            if (mainJobPage != null)
            {
                WritelnLog("Page:" + mainJobPage.Page);
                WritelnLog("SearchJobID:" + mainJobPage.SearchJobId);
                WritelnLog("ClientID" + mainJobPage.ClientID);
                WritelnLog("PageState" + mainJobPage.PageState);

                WritelnLog("Downloading ImageInfo...");
                List<ImageInfo> list = downloadImageList(mainJobPage, searchJob);
                WritelnLog("Download Done. pageId: " + mainJobPage.Id + " ||| num: " + list.Count);

                e.Msg = ConsumeAndProduceFactory.FactoryMsg.ProducingOk;
                foreach (ImageInfo ii in list)
                {
                    e.Products.Add(ii);
                }
                SpiderMsg msg = new SpiderMsg();
                msg.FinishJobPage = true;
                msg.PageId = mainJobPage.Id;
                e.Products.Add(msg);
            }
            else
            {
                e.Msg = ConsumeAndProduceFactory.FactoryMsg.ProducingFinished;
                e.Products = null;
            }
        }

        // 消费
        public void uploadImageInfo(object sender, ConsumeAndProduceFactory.FactoryEventArgs e)
        {
            WritelnLog("Uploading ImageInfo...");
            int count = 0;
            foreach (object ob in e.Products)
            {
                if (ob is SpiderMsg)
                {
                    SpiderMsg msg = (SpiderMsg)ob;
                    if (msg.FinishJobPage)
                    {
                        flyingPig.finishJobPage(msg.PageId);
                    }
                    continue;
                }

                count++;
                ImageInfo ii = (ImageInfo)ob;
                //经由API调用将ImageInfo上传至服务器
                
                FlyingPigSTATUS status = FlyingPig.uploadImageInfo(ii);
                if (count % 100 == 0)
                {
                    WritelnLog(System.Threading.Thread.CurrentThread.Name + " ||| " + " pageID is " + ii.PageId + ", count is " + count.ToString() + " ||| " +status.ToString());
                }
                if (status.Equals(FlyingPigSTATUS.SERVER_INNER_FAILED))
                {
                    break;
                }
            }
            WritelnLog("Upload Done ||| count is " + count.ToString());
        }

        // 批量生产
        public void spideImageInfos(object sender, ConsumeAndProduceFactory.FactoryEventArgs e)
        {
            JobPage mainJobPage = FlyingPig.requestJobPage(searchJob.SearchJobId);

            if (mainJobPage != null)
            {
                WritelnLog("Page:" + mainJobPage.Page);
                WritelnLog("SearchJobID:" + mainJobPage.SearchJobId);
                WritelnLog("ClientID" + mainJobPage.ClientID);
                WritelnLog("PageState" + mainJobPage.PageState);

                WritelnLog("Downloading ImageInfo...");
                List<ImageInfo> list = downloadImageList(mainJobPage, searchJob);
                WritelnLog("Download Done. pageId: " + mainJobPage.Id + " ||| num: " + list.Count);

                e.Msg = ConsumeAndProduceFactory.FactoryMsg.ProducingOk;
                e.Products.Add(list);
            }
            else
            {
                e.Msg = ConsumeAndProduceFactory.FactoryMsg.ProducingFinished;
                e.Products = null;
            }

        }

        // 批量消费
        public void uploadImageInfos(object sender, ConsumeAndProduceFactory.FactoryEventArgs e)
        {
            WritelnLog("Uploading ImageInfos...");
            List<ImageInfo> imageInfos = new List<ImageInfo>();
            foreach (object ob in e.Products)
            {
                List<ImageInfo> ii_list = (List<ImageInfo>)ob;
                if (ii_list.Count == 0)
                {
                    WritelnLog("==========批量消费 错误 list为空=============");
                    return;
                }

                //经由API调用将ImageInfo上传至服务器
                int successNum = FlyingPig.uploadImageInfos(ii_list);
                ImageInfo ii = ii_list[0];
                WritelnLog("Upload ||| " + " pageID is " + ii.PageId + " ||| total:" + ii_list.Count + " ||| success:" + successNum.ToString());
            }
        }

        public List<ImageInfo> downloadImageList(JobPage page, SearchJob job)
        {
            List<ImageInfo> list = new List<ImageInfo>();
            
            //使用Flickr API KEY，可能过期，过期后需要重新获得
            Flickr flickr = new Flickr(flickrapiKey, flickrsharedSecret);
            PhotoSearchOptions options = new PhotoSearchOptions();

            options.Tags = job.Concept.Replace("_", ",");
            options.PerPage = 500;
            options.Extras = PhotoSearchExtras.Tags;
            // 页面容量是 小时； page是逻辑第几页
            options.MaxUploadDate = job.getTime().AddHours(-1 * (page.Page - 1) * job.PageCapacity);
            options.MinUploadDate = job.getTime().AddHours(-1 * page.Page * job.PageCapacity);

            int curPage = 1;
            int totalPages = 1;
            int count = 0;
            do
            {
                try
                {
                    options.Page = curPage;
                    PhotoCollection photos = flickr.PhotosSearch(options);
                    totalPages = photos.Pages;
                    curPage++;


                    foreach (Photo photo in photos)
                    {
                        count++;
                        String photoUrl = String.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg", photo.Farm, photo.Server, photo.PhotoId, photo.Secret);

                        String tags = String.Empty;
                        foreach (String tag in photo.Tags)
                        {
                            tags += tag + ",";
                        }
                        tags = tags.TrimEnd(",".ToCharArray()).Trim();

                        //if (count % 100 == 0)
                        //{
                        //    WritelnLog(count.ToString() + ": " + photoUrl + " ||| option.page: " + page.Page);
                        //}

                        list.Add(new ImageInfo(photoUrl, photo.WebUrl.ToString(), tags, photo.PhotoId, photo.UserId, job.Concept, page.Id));
                    }

                }
                catch (Exception e)
                {
                    WritelnLog("FLICKR 搜索错误");
                    continue;
                }
            } while (curPage <= totalPages);

            return list;
        }
    }
}
